package com.xyy.saas.payment.adpater.jd.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xyy.saas.common.util.IdWorker;
import com.xyy.saas.payment.adpater.jd.common.JDConstants;
import com.xyy.saas.payment.adpater.jd.utils.JDGsonUtil;
import com.xyy.saas.payment.adpater.jd.utils.JDRequestUtils;
import com.xyy.saas.payment.adpater.jd.vo.aggrate.*;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.enums.JDPayTradeStatusEnum;
import com.xyy.saas.payment.cores.enums.ResultCodeEnum;
import com.xyy.saas.payment.util.ApolloUtil;
import com.xyy.saas.payment.util.DateUtil;
import com.xyy.saas.payment.util.PojoConvertUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 对接京东聚合接口服务类
 */
@Slf4j
@Component
public class JDAggregateAdpaterService {

    /**
     * 京东聚合支付 - 三方聚合统一下单
     */
    public JdPayAggregateCreateOrderResponse aggregateCreateOrder(String logPrefix, JdPayAggregateCreateOrderVo param) throws Exception {
        log.info("{} 京东聚合支付-三方聚合统一下单请求:{}", logPrefix, JSON.toJSONString(param));
        // 1、参数校验
        PojoConvertUtil.checkBlank(param, Arrays.asList("merchantNo", "outTradeNo", "tradeAmount", "tradeSubject", "tradeRemark", "tradeType", "sceneType"));
        JdPayAggregateCreateOrderRequest request = PojoConvertUtil.convertPojo(param, JdPayAggregateCreateOrderRequest::new);
        // 2、设置基础参数
        if (StringUtils.isBlank(request.getTradeExpiryTime()) || "0".equals(request.getTradeExpiryTime())) {
            log.info("{} 失效时间错误，设置默认失效时间:{}", logPrefix, param.getOutTradeNo());
            request.setTradeExpiryTime(ApolloUtil.getProperty(Constants.EXPIRE_JDAGGREGATE_TIME, "30"));
        }
        if (StringUtils.isBlank(request.getCreateDate())) {
            request.setCreateDate(DateUtil.format(new Date(), DateUtil.YYYYMMDDHHMMSS));
        }
        if (StringUtils.isBlank(request.getCurrency())) {
            request.setCurrency(JDConstants.AGGRATE_CURRENCY);
        }
        if (StringUtils.isBlank(request.getBizTp())) {
            request.setBizTp(JDConstants.BIZ_TYPE);
        }
        if (StringUtils.isBlank(request.getUserIp())) {
            request.setUserIp(JDConstants.AGGRATE_USER_IP);
        }
        if (StringUtils.isBlank(request.getMessageFormat())) {
            request.setMessageFormat(JDConstants.AGGRATE_MESSAGE_FORMAT);
        }
        if (StringUtils.isBlank(request.getOrderType())) {
            request.setOrderType(JDConstants.AGGRATE_ORDER_TYPE);
        }
        JSONObject returnParams = new JSONObject();
        returnParams.put("merchantNo", param.getMerchantNo());
        request.setReturnParams(returnParams.toJSONString());
        request.setNotifyUrl(ApolloUtil.getProperty("jd.notifyUrl") + Constants.CHANNEL_JDAGGREGATE_NAME + "/" + Constants.METHOD_PAY_SUCCESS_NAME);
        // 3、设置分账信息
        List<JdPayAggregateDivisionAccountTradeInfo> divisionAccountTradeInfoList = new ArrayList<>();
        divisionAccountTradeInfoList.add(JdPayAggregateDivisionAccountTradeInfo.builder().merchantNo(JDConstants.merchantSubMerchant(logPrefix, param.getMerchantNo())).outTradeNo(param.getOutTradeNo()).tradeAmount(param.getTradeAmount()).build());
        request.setDivisionAccount(JSONObject.toJSONString(JdPayAggregateDivisionAccount.builder().version(JDConstants.AGGRATE_VERSION).divisionAccountTradeInfoList(divisionAccountTradeInfoList).build()));
        if (param.getMerchantNo().equals("133400097002")) {
            request.setDivisionAccount(null);
        }
        // 4、发起请求
        JdPayAggregateCreateOrderResponse response = this.baseExecute(logPrefix, param.getMerchantNo(), JDConstants.AGGREGATE_CREATE_ORDER_URL, JSON.toJSONString(request), JdPayAggregateCreateOrderResponse.class);
        log.info("{} 京东聚合支付-三方聚合统一下单结果为：{}", logPrefix, JSONObject.toJSONString(response));
        if (!JDConstants.SUCCESS_CODE_AGGRATE.equals(response.getResultCode())) {
            throw new PaymentException(response.getResultCode(), JDConstants.transMsg(logPrefix, response.getResultCode(), response.getResultDesc()));
        }
        return response;
    }

    /**
     * 京东聚合支付 - 退款
     */
    public JdPayAggregateRefundResponse aggrateRefund(String logPrefix, JdPayAggregateRefundVo param) throws Exception {
        log.info("{} 京东聚合支付-退款请求:{}", logPrefix, JSON.toJSONString(param));
        // 1、参数校验
        PojoConvertUtil.checkBlank(param, Arrays.asList("merchantNo", "originalOutTradeNo", "outTradeNo", "tradeAmount"));
        JdPayAggregateRefundRequest request = PojoConvertUtil.convertPojo(param, JdPayAggregateRefundRequest::new);
        // 2、设置基础参数
        if (StringUtils.isBlank(request.getTradeDate())) {
            request.setTradeDate(DateUtil.format(new Date(), DateUtil.YYYYMMDDHHMMSS));
        }
        if (StringUtils.isBlank(request.getCurrency())) {
            request.setCurrency(JDConstants.AGGRATE_CURRENCY);
        }
        JSONObject returnParams = new JSONObject();
        returnParams.put("merchantNo", param.getMerchantNo());
        returnParams.put("originalOutTradeNo", request.getOriginalOutTradeNo());
        request.setReturnParams(returnParams.toJSONString());
        request.setNotifyUrl(ApolloUtil.getProperty("jd.notifyUrl") + Constants.CHANNEL_JDAGGREGATE_NAME + "/" + Constants.METHOD_REFUND_SUCCESS);
        // 3、设置分账信息
        List<JdPayAggregateDivisionAccountRefundInfo> divisionAccountRefundInfoList = new ArrayList<>();
        divisionAccountRefundInfoList.add(JdPayAggregateDivisionAccountRefundInfo.builder().merchantNo(JDConstants.merchantSubMerchant(logPrefix, param.getMerchantNo())).outTradeNo(param.getOutTradeNo()).originalOutTradeNo(param.getOriginalOutTradeNo()).outTradeNo(request.getOutTradeNo()).tradeAmount(request.getTradeAmount()).build());
        request.setDivisionAccountRefund(JSONObject.toJSONString(JdPayAggregateDivisionAccountRefund.builder().version(JDConstants.AGGRATE_VERSION).divisionAccountRefundInfoList(divisionAccountRefundInfoList).build()));
        if (param.getMerchantNo().equals("133400097002")) {
            request.setDivisionAccountRefund(null);
        }
        // 4、发起请求
        JdPayAggregateRefundResponse response = this.baseExecute(logPrefix, param.getMerchantNo(), JDConstants.REFUND_URL, JSON.toJSONString(request), JdPayAggregateRefundResponse.class);
        log.info("{} 京东聚合支付-退款结果为：{}", logPrefix, JSONObject.toJSONString(response));
        if (!JDConstants.SUCCESS_CODE_AGGRATE.equals(response.getResultCode())) {
            throw new PaymentException(response.getResultCode(), JDConstants.transMsg(logPrefix, response.getResultCode(), response.getResultDesc()));
        }
        if (JDPayTradeStatusEnum.CLOS.getCode().equals(response.getTradeStatus())) {
            throw new PaymentException(ResultCodeEnum.JD_REFUND_ERROR.getCode(), ResultCodeEnum.JD_REFUND_ERROR.getDisplayMsg());
        }
        return response;
    }

    /**
     * 京东聚合支付 - 支付订单查询 ：查询订单信息 -  包括首次支付订单与代扣订单
     */
    public JdPayAggregateQueryOrderResponse queryAggrateOrder(String logPrefix, JdPayAggregateQueryOrderVo param) throws Exception {
        log.info("{} 京东聚合支付-支付订单查询请求:{}", logPrefix, JSON.toJSONString(param));
        // 1、参数校验
        PojoConvertUtil.checkBlank(param, Arrays.asList("merchantNo", "outTradeNo"));
        JdPayAggregateQueryOrderRequest request = PojoConvertUtil.convertPojo(param, JdPayAggregateQueryOrderRequest::new);
        // 2、发起请求
        JdPayAggregateQueryOrderResponse response = this.baseExecute(logPrefix, param.getMerchantNo(), JDConstants.TRADE_QUERY_URL, JSON.toJSONString(request), JdPayAggregateQueryOrderResponse.class);
        log.info("{} 京东聚合支付-支付订单查询结果为：{}", logPrefix, JSONObject.toJSONString(response));
        if (!JDConstants.SUCCESS_CODE_AGGRATE.equals(response.getResultCode())) {
            throw new PaymentException(response.getResultCode(), JDConstants.transMsg(logPrefix, response.getResultCode(), response.getResultDesc()));
        }
        return response;
    }

    /**
     * 京东聚合支付 - 退款查询
     */
    public JdPayAggregateRefundQueryResponse queryAggrateRefund(String logPrefix, JdPayAggregateRefundQueryVo param) throws Exception {
        log.info("{} 京东聚合支付-退款查询请求:{}", logPrefix, JSON.toJSONString(param));
        // 1、参数校验
        PojoConvertUtil.checkBlank(param, Arrays.asList("merchantNo", "outTradeNo"));
        JdPayAggregateRefundQueryRequest request = PojoConvertUtil.convertPojo(param, JdPayAggregateRefundQueryRequest::new);
        // 2、发起请求
        JdPayAggregateRefundQueryResponse response = this.baseExecute(logPrefix, param.getMerchantNo(), JDConstants.REFUND_QUERY_URL, JSON.toJSONString(request), JdPayAggregateRefundQueryResponse.class);
        log.info("{} 京东聚合支付-退款查询结果为：{}", logPrefix, JSONObject.toJSONString(response));
        if (!JDConstants.SUCCESS_CODE_AGGRATE.equals(response.getResultCode())) {
            throw new PaymentException(response.getResultCode(), JDConstants.transMsg(logPrefix, response.getResultCode(), response.getResultDesc()));
        }
        return response;
    }

    /**
     * 京东聚合支付 - 关单
     */
    public JdPayAggregateCloseResponse aggrateClose(String logPrefix, JdPayAggregateCloseVo param) throws Exception {
        log.info("{} 京东聚合支付-关单请求:{}", logPrefix, JSON.toJSONString(param));
        // 1、参数校验
        PojoConvertUtil.checkBlank(param, Arrays.asList("merchantNo", "orignalOutTradeNo"));
        JdPayAggregateCloseRequest request = PojoConvertUtil.convertPojo(param, JdPayAggregateCloseRequest::new);
        // 2、发起请求
        JdPayAggregateCloseResponse response = this.baseExecute(logPrefix, param.getMerchantNo(), JDConstants.CLOSE_URL, JSON.toJSONString(request), JdPayAggregateCloseResponse.class);
        log.info("{} 京东聚合支付-关单结果为：{}", logPrefix, JSONObject.toJSONString(response));
        if (!JDConstants.SUCCESS_CODE_AGGRATE.equals(response.getResultCode())) {
            throw new PaymentException(response.getResultCode(), JDConstants.transMsg(logPrefix, response.getResultCode(), response.getResultDesc()));
        }
        return response;
    }

    /**
     * 执行接口调用
     */
    private <REQ, RES> RES baseExecute(String logPrefix, String merchantNo, String url, String jsonParam, Class<RES> clazz) throws Exception {
        // 1、组装公共参数
        Map<String, String> commonParam = fillCommonParam(merchantNo, String.valueOf(IdWorker.generaterId()));
        // 2、发起请求
        String respJson = JDRequestUtils.tradeRequestSSL(logPrefix + ":aggrate", merchantNo, commonParam, jsonParam, url);
        // 3、验证签名并获取返回结果
        JSONObject jsonObject = JDRequestUtils.verifySignAndReturn(logPrefix, merchantNo, respJson);
        // 4、返回数据
        return JDGsonUtil.fromJson(jsonObject.toJSONString(), clazz);
    }

    /**
     * 组装api公共参数赋值
     */
    private static Map<String, String> fillCommonParam(String merchantNo, String reqNo) {
        Map<String, String> reqMap = new HashMap<>();
        // 二级商户号
        reqMap.put("merchantNo", merchantNo);
        // 商户生成的唯一标识，可以与outTradeNo一致
        reqMap.put("reqNo", reqNo);
        // 字符集
        reqMap.put("charset", JDConstants.CHARSET_UTF8);
        // 固定值
        reqMap.put(JDConstants.PARAM_FORMAT_TYPE, JDConstants.DATA_FORMAT_TYPE_JSON);
        // 签名类型
        reqMap.put(JDConstants.PARAM_SIGN_TYPE, JDConstants.SING_TYPE);
        // 固定值，证书加密
        reqMap.put(JDConstants.PARAM_ENC_TYPE, JDConstants.ENCRYPT_TYPE_AP7);
        return reqMap;
    }

}
